import re
import subprocess
import json
from typing import Dict, List
from collections import defaultdict
from datetime import datetime

class LogAnalyzer:
    def __init__(self):
        self.keyword_patterns = {
            'ECC': r'ECC|Memory|DIMM',
            'PSU': r'Power Supply|PSU|Voltage|AC lost',
            'TEMP': r'Temperature|Thermal',
            'FAN': r'Fan|Cooling',
            'CRITICAL': r'Critical|Fatal|Error'
        }
        
        self.filter_patterns = [
            r'Timestamp Clock Sync',
            r'Pre-Init',
            r'^$'
        ]

    def bash(self, cmd: str) -> str:
        try:
            return subprocess.check_output(cmd, shell=True, executable='/bin/bash', stderr=subprocess.STDOUT).decode().strip()
        except subprocess.CalledProcessError as e:
            return e.output.decode().strip()

    def smart_disk_check(self):
        """简化的硬盘 SMART 状态检查"""
        smart_check_cmd = "for i in $(ls /dev/ | grep -E '^sd[a-z]+$|^nvme[0-9]+n1$'); do smartctl -H /dev/$i | grep -i 'result'; done"
        smart_output = self.bash(smart_check_cmd)
        
        if 'FAILED' in smart_output.upper():
            return {'status': 'FAIL', 'details': smart_output}
        else:
            return {'status': 'PASS', 'details': smart_output}

    def sn_get(self):
        """获取服务器序列号"""
        srvSn = self.bash("dmidecode -t system | grep 'Serial Number' | awk -F: '{print $2}'|sed 's/ //g'")
        if srvSn == "ToBeFilledByO.E.M.":
            srvSn = self.bash("ipmitool fru|grep Serial|awk -F: '{print $2}'|sed 's/ //g'")
        return srvSn

    def analyze_log(self, content: str) -> Dict[str, List[str]]:
        lines = [line for line in content.split('\n') if line.strip() 
                 and not any(re.search(pat, line, re.IGNORECASE) for pat in self.filter_patterns)]

        results = defaultdict(list)
        remaining = []

        for line in lines:
            matched = False
            for category, pattern in self.keyword_patterns.items():
                if re.search(pattern, line, re.IGNORECASE):
                    results[category].append(line)
                    matched = True
                    break
            if not matched:
                remaining.append(line)

        if remaining:
            results['Other'] = remaining
        return dict(results)

    def get_system_info(self):
        """获取详细系统信息"""
        return {
            'Chassis & Device Info': self.bash("dmidecode -t 1"),
            'PCI': self.bash("lspci |grep -Ei 'sas|raid|eth|infi|nvidia'"),
            'BMC - FRU': self.bash("ipmitool fru print"),
            'BMC - LAN': self.bash("ipmitool lan print 1"),
            'BMC - User': self.bash("ipmitool user list 1 | grep -Evi 'NO ACCESS'"),
            'CPU': self.bash("lscpu|grep -Ev 'Vulner|Flags'"),
            'Memory': self.bash("""dmidecode -t 17 | perl -ne 'BEGIN{$/=""} 
                if (/Size:\s*(\d+\s*MB)?/ && !/No Module/) {
                    @fields = (/(?:Size|Locator|Speed|Manufacturer|Serial Number|Part Number):\s*(.+?)(?=\n|$)/g);
                    print join("\t", map{s/^\s+|\s+$//gr} @fields), "\n"
                }'"""),
            'Disk': self.bash("lsblk -o NAME,FSTYPE,LABEL,MOUNTPOINT,SIZE,MODEL,SERIAL,STATE,VENDOR")
        }

    def save_log(self, content: str, filename: str):
        """保存日志文件"""
        with open(filename, 'w') as f:
            f.write(content)

    def process_logs(self):
        """处理日志并收集信息"""
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        
        log_files = {
            'dmesg': self.bash("dmesg --level emerg,alert,err | grep -Ev 'overriding NVDATA|Failed to start|SGX disabled'"),
            'sel': self.bash("ipmitool sel elist"),
            'sdr': self.bash("ipmitool sdr|grep -Ev 'ok|ns'")
        }

        sn = self.sn_get()

        log_paths = {}
        for log_type, content in log_files.items():
            log_path = f'/tmp/{log_type}_{timestamp}.log'
            self.save_log(content, log_path)
            log_paths[log_type] = log_path

        # 分析日志
        log_analysis = {
            'DMESG': self.analyze_log(log_files['dmesg']),
            'SEL': self.analyze_log(log_files['sel']),
            'SDR': self.analyze_log(log_files['sdr'])
        }

        stone_check_log = self.bash("cat /tmp/stone-check.log")

        smart_check = self.smart_disk_check()

        return {
            'SerialNumber': sn,
            'LogFiles': log_paths,
            'System_Info': self.get_system_info(),
            'Log_Analysis': log_analysis,
            'STONE_Check': stone_check_log,
            'SMART_Check': smart_check
        }

    def evaluate_test_status(self, results):
        """评估测试状态"""
        status = {
            'STONE_Check': 'FAIL' if 'FAIL' in results['STONE_Check'] else 'PASS',
            'DMESG': 'PASS' if not results['Log_Analysis']['DMESG'] else 'WARN',
            'SEL': 'WARN' if results['Log_Analysis']['SEL'] and 'Other' not in results['Log_Analysis']['SEL'] else 'PASS',
            'SDR': 'PASS' if not results['Log_Analysis']['SDR'] else 'WARN',
            'SMART': results['SMART_Check']['status']
        }
        
        all_test_result = 'FAIL' if 'FAIL' in status.values() else 'WARN' if 'WARN' in status.values() else 'PASS'
        
        return status, all_test_result

    def generate_report(self, results, test_status, all_test_result):
        """生成详细报告"""
        report_file = f'/tmp/server_health_report_{datetime.now().strftime("%Y%m%d_%H%M%S")}.log'
        
        with open(report_file, 'w') as f:
            # 写入序列号
            f.write(f"服务器序列号: {results['SerialNumber']}\n\n")

            # 系统信息
            f.write("=== 系统详细信息 ===\n")
            for key, value in results['System_Info'].items():
                f.write(f"{key}:\n{value}\n\n")

            # 日志分析
            f.write("=== 日志分析 ===\n")
            log_types = ['DMESG', 'SEL', 'SDR']
            for log_type in log_types:
                f.write(f"{log_type} 日志分析:\n")
                if results['Log_Analysis'][log_type]:
                    for category, events in results['Log_Analysis'][log_type].items():
                        f.write(f"{category}: {len(events)} events\n")
                        if category != 'Other':
                            for event in events:
                                f.write(f"  - {event}\n")
                else:
                    f.write("No abnormal events\n")
                f.write("\n")

            # 压测日志
            f.write("=== MES压测日志 ===\n")
            f.write(results['STONE_Check'] + "\n\n")

            # SMART 检查
            f.write("=== 磁盘 SMART 状态 ===\n")
            f.write(f"检查结果: {results['SMART_Check']['status']}\n")
            f.write("详细信息:\n")
            f.write(results['SMART_Check']['details'] + "\n\n")

            # 测试状态
            f.write("=== 测试状态 ===\n")
            for key, value in test_status.items():
                f.write(f"{key}: {value}\n")
            
            f.write(f"\n总体测试结果: {all_test_result}")

        print(f"详细报告已保存至: {report_file}")
        return report_file

def main():
    analyzer = LogAnalyzer()
    results = analyzer.process_logs()
    test_status, all_test_result = analyzer.evaluate_test_status(results)

    # 生成详细报告
    report_path = analyzer.generate_report(results, test_status, all_test_result)

    # 控制台输出概要
    print("\n=== 服务器健康检查概要 ===")
    print(f"服务器序列号: {results['SerialNumber']}")
    print(f"总体测试结果: {all_test_result}")
    print(f"详细报告位置: {report_path}")
    analyzer.bash("/root/scripts/stone-server-check/src/client/scripts/upload.sh")

if __name__ == "__main__":
    main()
